package com.startx.http.system.encrypt.rsa;

import java.io.BufferedReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;

import org.apache.log4j.Logger;

import com.startx.http.system.encrypt.base64.Base64;

public class RSA {

	private static final Logger Log4j = Logger.getLogger(RSA.class);
	private static PublicKey publicKey;
	private static PrivateKey privateKey;

	/**
	 * 生成公钥私钥
	 */
	public static void generateKeyPair(String public_path, String private_path, int bits) {

		FileWriter pub_writer = null;
		FileWriter pri_writer = null;
		try {
			KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
			kpg.initialize(bits);// initialize key pairs to 512 bits ,you can
									// also take 1024 or 2048 bits
			KeyPair kp = kpg.genKeyPair();

			PublicKey publicKey = kp.getPublic();
			PrivateKey privateKey = kp.getPrivate();

			byte[] pub_rsa = Serializer.serialize(publicKey);
			byte[] pri_rsa = Serializer.serialize(privateKey);

			String base64_pub = Base64.encode(pub_rsa);
			String base64_pri = Base64.encode(pri_rsa);

			pub_writer = new FileWriter(public_path);
			pri_writer = new FileWriter(private_path);

			pub_writer.write(base64_pub);
			pri_writer.write(base64_pri);

		} catch (Exception e) {
			Log4j.fatal(e.getMessage(), e);
		} finally {

			try {
				if (pub_writer != null)
					pub_writer.close();
				if (pri_writer != null)
					pri_writer.close();
			} catch (IOException e) {
				Log4j.fatal(e.getMessage(), e);
			}

		}

	}

	/**
	 * 初始化RSA
	 */
	public static void init(InputStream pub, InputStream pri) {
		publicKey = (PublicKey) Serializer.deserialize(Base64.decode(readPublicKey(pub)));
		privateKey = (PrivateKey) Serializer.deserialize(Base64.decode(readPrivateKey(pri)));
	}

	/**
	 * 初始化RSA
	 */
	public static void init(String pub, String pri) {
		publicKey = (PublicKey) Serializer.deserialize(Base64.decode(pub));
		privateKey = (PrivateKey) Serializer.deserialize(Base64.decode(pri));
	}

	/**
	 * 读取公钥
	 * @param public_path
	 * @return
	 */
	private static String readPublicKey(InputStream public_path) {

		BufferedReader public_file = null;

		try {

			public_file = new BufferedReader(new InputStreamReader(public_path));
			StringBuilder builder = new StringBuilder();
			String line = "";

			while ((line = public_file.readLine()) != null) {
				builder.append(line);
			}

			return builder.toString();

		} catch (Exception e) {
			Log4j.fatal(e.getMessage(), e);
		} finally {
			try {
				if (public_file != null)
					public_file.close();
			} catch (IOException e) {
				Log4j.fatal(e.getMessage(), e);
			}
		}
		return "";
	}

	/**
	 * 读取私钥
	 * @param private_path
	 * @return
	 */
	private static String readPrivateKey(InputStream private_path) {

		BufferedReader private_file = null;

		try {

			private_file = new BufferedReader(new InputStreamReader(private_path));
			StringBuilder builder = new StringBuilder();
			String line = "";

			while ((line = private_file.readLine()) != null) {
				builder.append(line);
			}

			return builder.toString();

		} catch (Exception e) {
			Log4j.fatal(e.getMessage(), e);
		} finally {
			try {
				if (private_file != null)
					private_file.close();
			} catch (IOException e) {
				Log4j.fatal(e.getMessage(), e);
			}
		}
		return "";
	}
	
	/**
	 * 加密原文
	 * @param source
	 * @return
	 */
	public static String encrypt(String source) {
		try {
			Cipher cipher = Cipher.getInstance("RSA/ECB/NoPadding");
			cipher.init(Cipher.ENCRYPT_MODE, publicKey);
			return Base64.encode(cipher.doFinal(source.getBytes()));
		} catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException | IllegalBlockSizeException
				| BadPaddingException e) {
			Log4j.fatal(e.getMessage(), e);
		}
		return "";
	}
	
	/**
	 * 解密密文
	 * @param source
	 * @return
	 */
	public static String decrypt(String source) {
		try {
			Cipher cipher = Cipher.getInstance("RSA/ECB/NoPadding");
			cipher.init(Cipher.DECRYPT_MODE, privateKey);
			byte[] result = Base64.decode(source);
			return new String(cipher.doFinal(result));
		} catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException | IllegalBlockSizeException
				| BadPaddingException e) {
			Log4j.fatal(e.getMessage(), e);
		}
		return "";
	}
}
